package com.blockmeta.bbs.businesslibrary.widget.chartview.Layer;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;


import com.blockmeta.bbs.businesslibrary.websocket.AppDefine;
import com.blockmeta.bbs.businesslibrary.websocket.Symbol;
import com.blockmeta.bbs.businesslibrary.widget.chartview.Axis.Coordinate;
import com.blockmeta.bbs.businesslibrary.widget.chartview.CandleData;
import com.blockmeta.bbs.businesslibrary.widget.chartview.ChartData;
import com.blockmeta.bbs.businesslibrary.widget.chartview.CoinChart;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;

public class Layer
{
	public static final String LAYER_ID = "Layer-ID";
	public static final String BASIC_LAYER = "Basic-Layer";

	public enum ChartTypeEnum
	{
		 KBAR(1, KBarLayer.class), AREA(2, AreaLayer.class), BAR(3, BarLayer.class), DAILY(4, DailyLayer.class),
		MACD(5, MACDLayer.class), RSI(6,RSILayer.class),KDJ(7,KDJLayer.class),KMoveBar(8,KBarMoveLayer.class),
		MoveBar(9,BarMoveLayer.class),MoveLine(10,MoveLineLayer.class),DAILYBAR(11, DailyBarLayer.class),
		KMaMoveBar(12,KBarMaMoveLayer.class),KBollMoveBar(13,KBarBollMoveLayer.class),OBV(14,OBVLayer.class),
		CCI(15,CCILayer.class),WR(16,WRLayer.class),ROC(17,ROCLayer.class),STOCHTSI(18,STOCHRSILayer.class),Depth(19, DepthLayer.class),
		MarketRank(20, MarketRankLayer.class);

		int ID;
		Class<? extends BasicLayer> m_class;

		ChartTypeEnum(int pID, Class<? extends BasicLayer> pClass)
		{
			ID = pID;
			m_class = pClass;
		}

		public static ChartTypeEnum fromID(int pID)
		{
			for (ChartTypeEnum tType : values())
			{
				if (tType.ID == pID)
				{
					return tType;
				}
			}
			return KBAR;
		}

		public Class<? extends BasicLayer> getObjectClass()
		{
			return m_class;
		}
	}

	private ChartTypeEnum m_chartType;

	private Coordinate m_coordinate = null;
	private BasicLayer m_layerType = null;
	private RectF m_rect = null;
	private boolean m_bIsShowLayer = true;
	private boolean m_bIsShowOutRect = false;//显示layer外面的框


	private LayerCallback m_callback = null;
	private ChartData m_chartData = null;
	private CandleData m_lastData = null;
	private final float m_fDrawRate = 0.03f;
	private boolean m_bIsCrossOutter = true;

	private boolean m_bIsShowCoordinate = true;
	private boolean m_bIsShowPercentAxis = false;

	private boolean m_bIsOnlyShowSquareNum = false;

	private boolean m_bIsNeedUpDownSpace = false;
	private int m_nMACount = 5;
	private int m_color = 0xFF007AFF;

	private boolean m_bNeedCross = false;
	private boolean m_bNeedFloatPanel = false;

	private boolean m_bNeedFloatIndicatorText = false;
	private String m_strID;
	private int m_YTagCount;
	private boolean m_bIsShowShadow;
	private boolean m_drawAllData = false;
	private boolean m_bIsShowMaxMinArrow = false;
	private boolean m_bIsShowXAxisAtButtom = false;


	private List<CandleData> m_AdditonData;
	/**
	 * Create a new Layer by the LayerType and RectF.
	 * 
	 * RectF(left-offset, top-offset, width, height): All params just be 0 to 1,
	 * that meaning the weight of each params.
	 * */
	public Layer(ChartTypeEnum pType, RectF pRect, String pID)
	{
		m_strID = pID;
		checkRectF(pRect);
		setType(pType, false);
		m_coordinate = m_layerType.createCoordinate();
		m_coordinate.setCallback(new Coordinate.CoordinateCallback()
		{
			@Override
			public int getXTagCount()
			{
				if (m_callback == null)
				{
					return 3;
				}
				else
				{
					return m_callback.getXTagCount();
				}
			}

			@Override
			public ChartTypeEnum getCharTypeEnum()
			{
				return m_layerType.getLayerTypeEnum();
			}

			@Override
			public Rect getPanelRect()
			{
				if (m_callback == null)
				{
					return new Rect();
				}
				else
				{
					return m_callback.getPanelRect();
				}
			}

			@Override
			public boolean isSimpleMode()
			{
				if (m_callback == null)
				{
					return false;
				}
				else
				{
					return m_callback.isSimpleMode();
				}
			}

			@Override
			public boolean isShowYesterClose()
			{
				return m_layerType.isShowYesterClose();
			}

			@Override
			public float getYesterClose()
			{
				return m_layerType.getYesterClose();
			}

			@Override
			public boolean isCoordinateTextOuterY()
			{
				if (m_callback == null)
				{
					return true;
				}
				else
				{
					return m_callback.isCoordinateTextOuterY();
				}
			}

			@Override
			public int getDisplayCount()
			{
				return m_callback.getDisplayCount();
			}

			@Override
			public float getScaleFactor()
			{
				return m_callback.getScaleFactor();
			}

			@Override
			public int getYTagCount()
			{
				return m_YTagCount;
			}

			@Override
			public boolean isDrawAllData()
			{
				return isNeedDrawAllData();
			}

			@Override
			public List<CandleData> getAdditionMinMax()
			{
				return m_AdditonData;
			}

			@Override
			public boolean isCOnlyShowSquareNum()
			{
				return m_bIsOnlyShowSquareNum;
			}

			@Override
			public boolean isNeedUpDownSpace()
			{
				return m_bIsNeedUpDownSpace;
			}

			@Override
			public boolean isShowMaxMinArrow() {
				return m_bIsShowMaxMinArrow;
			}
		});
	}

	public void setCallback(LayerCallback pCallback)
	{
		m_callback = pCallback;
	}

	public void setIsShowXAxis(boolean pIsShowAxis)
	{
		m_coordinate.setIsShowXAxis(pIsShowAxis);
	}

	public void setIsShowYAxis(boolean pIsShowAxis)
	{
		m_coordinate.setIsShowYAxis(pIsShowAxis);
	}

	public void setIsShowXCoordinate(boolean pIsShow)
	{
		m_coordinate.setIsShowXCoordinate(pIsShow);
	}

	public void setIsShow0LineCoordinate(boolean pIsShow)
	{
		m_coordinate.setIsShow0LineCoordinate(pIsShow);
	}

	public void setXTagCount(int num)
	{
		m_coordinate.setTagXCount(num);
	}

	public void setYTagCount(int m_YTagCount)//设置后可以只显示两个y坐标，用于y坐标内收时用
	{
		this.m_YTagCount = m_YTagCount;
	}


	public void setIsShowShadow(boolean pIsShowShadow)//设置后显示阴影
	{
		this.m_bIsShowShadow = pIsShowShadow;
	}

	public void setIsOnlyShowSquareNum(boolean m_bIsOnlyShowSquareNum)
	{
		this.m_bIsOnlyShowSquareNum = m_bIsOnlyShowSquareNum;
	}

	public boolean isNeedDrawAllData()
	{
		return m_drawAllData;
	}

	public void setIsDrawAllData(boolean m_drawAllData)
	{
		this.m_drawAllData = m_drawAllData;
	}

	public void setIsShowYCoordinate(boolean pIsShow)
	{
		m_coordinate.setIsShowYCoordinate(pIsShow);
	}

	public void setIsNeedUpDownSpace(boolean m_bIsNeedUpDownSpace)
	{
		this.m_bIsNeedUpDownSpace = m_bIsNeedUpDownSpace;
	}

	public void isShowXTitle(boolean pShow)
	{
		m_coordinate.isShowXTitle(pShow);
	}

	public void isShowYTitle(boolean pShow)
	{
		m_coordinate.isShowYTitle(pShow);
	}

	public void setXTitle(String pTitle)
	{
		m_coordinate.setXTitle(pTitle);
	}

	public void setYTitle(String pTitle)
	{
		m_coordinate.setYTitle(pTitle);
	}

	public CoinChart.AxisPercentType isShowPercentAxis()
	{
		return m_coordinate.getIsShowPercent();
	}

	public boolean isShowXAxisAtButtom()
	{
		return m_bIsShowXAxisAtButtom;
	}

	public void setShowXAxisAtButtom(boolean isShow)
	{
		this.m_bIsShowXAxisAtButtom = isShow;
	}

	public void setIsShowPercentAxis(Symbol layerSymbol, boolean pIsShowPercentAxis)
	{

//		if (layerSymbol != null && pIsShowPercentAxis)
//		{
//			AppEnv.SubMarket subMarket = layerSymbol.getSubMarket();
//			AppEnv.AppMarket appMarket = layerSymbol.getMarket().getAppMarket();
//			if (subMarket == AppEnv.SubMarket.US || subMarket == AppEnv.SubMarket.HK)
//			{
//				m_coordinate.setIsShowPercent(FDTChart.AxisPercentType.BOTTOMPERCENT);
//			}
//			else if (appMarket == AppEnv.AppMarket.SC || appMarket == AppEnv.AppMarket.FC)
//			{
//				m_coordinate.setIsShowPercent(FDTChart.AxisPercentType.MIDDLEPERCENT);
//			}
//			else
//			{
//				m_coordinate.setIsShowPercent(FDTChart.AxisPercentType.BOTTOMPERCENT);
//			}
//		}
//		else
//		{
			m_coordinate.setIsShowPercent(CoinChart.AxisPercentType.BOTTOMPERCENT);
//		}
	}

	public void needCrossLine(boolean pBool)
	{
		m_bNeedCross = pBool;
	}

	public void needCrossFloatPannel(boolean pBool)
	{
		m_bNeedFloatPanel = pBool;
	}

	public void setNeedFloatIndicatorText(boolean m_bNeedFloatIndicatorText)
	{
		this.m_bNeedFloatIndicatorText = m_bNeedFloatIndicatorText;
	}
	public boolean isShowMaxMinArrow() {
		return m_bIsShowMaxMinArrow;
	}

	public void setIsShowMaxMinArrow(boolean m_bIsShowMaxMinArrow) {
		this.m_bIsShowMaxMinArrow = m_bIsShowMaxMinArrow;
	}
	public boolean IsShowOutRect()
	{
		return m_bIsShowOutRect;
	}

	public void setIsShowOutRect(boolean m_bIsShowOutRect)
	{
		this.m_bIsShowOutRect = m_bIsShowOutRect;
	}

	public boolean needCrossLing()
	{
		return m_bNeedCross;
	}


	public Coordinate getCoordinate()
	{
		return m_coordinate;
	}

	public void setData(ChartData chart, AppDefine.UpdateMode mode)
	{
		boolean tNeedRedraw = true;

		if (chart == null)
		{
			if (m_chartData != null)
			{
				m_chartData.clear();
				m_lastData = null;
			}
		}
		else
		{
			m_chartData = chart;

			List<CandleData> tCurrentData = null;
			CandleData candle = chart.getLastCandle();

			if (candle != null)
			{
				if (mode == AppDefine.UpdateMode.UPDATE)
				{
					if (m_lastData != null)
					{
						//判断是否要重画,如果k线图最后一个点超出0.03f;bar则必须重画
						float tDataDist = m_coordinate.getMaxValue() - m_coordinate.getMinValue();

						if (m_layerType.getLayerTypeEnum() == ChartTypeEnum.KBAR)
						{
							float tHighDistRate = Math.abs((float) candle.getDbHigh() - (float) m_lastData.getDbHigh()) / tDataDist;
							float tLowDistRate = Math.abs((float) candle.getDbLow() - (float) m_lastData.getDbLow()) / tDataDist;
							float tOpenDistRate = Math.abs((float) candle.getDbOpen() - (float) m_lastData.getDbOpen()) / tDataDist;
							float tCloseDistRate = Math.abs((float) candle.getDbClose() - (float) m_lastData.getDbClose()) / tDataDist;

							if (tHighDistRate <= m_fDrawRate && tLowDistRate <= m_fDrawRate && tOpenDistRate <= m_fDrawRate && tCloseDistRate <= m_fDrawRate)
							{
								tNeedRedraw = false;
							}
						}
						else if (m_layerType.getLayerTypeEnum() == ChartTypeEnum.BAR)
						{
						}
						else
						{
							float tValueDistRate = Math.abs((float) candle.getDbClose() - (float) m_lastData.getDbClose()) / tDataDist;
							if (tValueDistRate <= m_fDrawRate)
							{
								tNeedRedraw = false;
							}
						}
					}
				}

				if (tNeedRedraw)
				{
					m_lastData = candle.clone();
				}
			}


			m_layerType.onCalculateData();//数据集更新的时候去更新计算指标的数据，计算成功后替换当前数据源
		}


		m_coordinate.setData(m_chartData);

		if (m_callback != null && tNeedRedraw)
		{
			m_callback.NeedRedraw();
		}
	}

	/**
	 * 移动的时候没有更新数据源，只更新坐标值
	 */
	public void coordinateUpdate(int pdataIndex,float pdataIndexOffset)
	{
		if(m_chartData != null)
		{
			m_chartData.m_dataIndex = pdataIndex;
			m_chartData.m_dataIndexOffset = pdataIndexOffset;
			m_coordinate.setData(m_chartData);
		}
	}


	public void moveStartIndex(int pdist)
	{
		boolean success = m_coordinate.moveStartIndex(pdist);
		if(success && m_callback != null)
		{
			m_callback.NeedRedraw();
		}
	}

	public boolean canMoveIndex(int pdist)
	{
		boolean success = m_coordinate.canMoveIndex(pdist);
		return success;
	}

	public void setOriginPointLocation(CoinChart.PointLocation pLocation)
	{
		m_coordinate.setOriginPointLocation(pLocation);
	}

	public CoinChart.PointLocation getOriginPointLocation()
	{
		return m_coordinate.getOriginPointLocation();
	}

	public ChartTypeEnum getType()
	{
		return m_chartType;
	}


	public void setType(ChartTypeEnum pType)
	{
		setType(pType, true);
	}

	private void setType(ChartTypeEnum pType, boolean pNeedDraw)
	{
		m_chartType = pType;

		boolean tSuccess = false;
		Class<? extends BasicLayer> tClass = pType.getObjectClass();
		try
		{
			m_layerType = tClass.getConstructor(new Class<?>[]
			{}).newInstance(new Object[]
			{});
			tSuccess = true;
		}
		catch (InstantiationException e)
		{
			e.printStackTrace();
		}
		catch (IllegalAccessException e)
		{
			e.printStackTrace();
		}
		catch (IllegalArgumentException e)
		{
			e.printStackTrace();
		}
		catch (InvocationTargetException e)
		{
			e.printStackTrace();
		}
		catch (NoSuchMethodException e)
		{
			e.printStackTrace();
		}

		if (!tSuccess)
		{
			m_layerType = new AreaLayer();
		}

		m_layerType.setLayerTypeCallback(new BasicLayer.LayerTypeCallback()
		{
			@Override
			public void connectChartDataFinished()
			{
				if (m_callback != null)
				{
					m_callback.NeedRedraw();
				}
			}

			@Override
			public int getSysUpColor()
			{
				if (m_callback != null)
				{
					return m_callback.getSysUpColor();
				}
				else
				{
					return Color.RED;
				}
			}

			@Override
			public int getSysDownColor()
			{
				if (m_callback != null)
				{
					return m_callback.getSysDownColor();
				}
				else
				{
					return Color.GREEN;
				}
			}

			@Override
			public int getSysEvenColor()
			{
				if (m_callback != null)
				{
					return m_callback.getSysEvenColor();
				}
				else
				{
					return Color.BLUE;
				}
			}

			@Override
			public Coordinate getCoordinate()
			{
				return m_coordinate;
			}

			@Override
			public List<CandleData> getCandleDataList()
			{
				if (m_chartData != null)
				{
					return m_chartData.getCandleData();
				}
				return null;
			}

			@Override
			public int getSysBgColor()
			{
				if (m_callback != null)
				{
					return m_callback.getSysBgColor();
				}
				else
				{
					return Color.BLUE;
				}
			}

			@Override
			public void pointFeedback(HashMap<String, String> pData, Point pPoint)
			{
				if (m_callback != null)
				{
					pData.put(LAYER_ID, m_strID);
					m_callback.pointFeedback(pPoint,pData);
				}
			}

			@Override
			public ChartData.ChartPeroid getChartType()
			{
				if (m_chartData != null)
					return m_chartData.getChartPeroid();
				return ChartData.ChartPeroid.CP_5min;
			}

			@Override
			public int getDigit()
			{
				if (m_chartData != null)
					return m_chartData.getSymbol().getDigit();
				return 0;
			}

			@Override
			public boolean needCrossLine()
			{
				return m_bNeedCross;
			}

			@Override
			public boolean needFloatPanel()
			{
				return m_bNeedFloatPanel;
			}

			@Override
			public boolean needFloatIndicatorText()
			{
				return m_bNeedFloatIndicatorText;
			}

			@Override
			public boolean isCrossOutter()
			{
				return m_bIsCrossOutter;
			}

			@Override
			public int getColor()
			{
				return m_color;
			}

			@Override
			public int getMACount()
			{
				return m_nMACount;
			}

			@Override
			public Bitmap getArrowLeft()
			{
				if (m_callback != null)
				{
					return m_callback.getArrowLeft();
				}
				return null;
			}

			@Override
			public Bitmap getArrowRight()
			{
				if (m_callback != null)
				{
					return m_callback.getArrowRight();
				}
				return null;
			}

			@Override
			public int getDisplayCount()
			{
				return m_callback.getDisplayCount();
			}

			@Override
			public boolean isShowLayer()
			{
				return getShowLayer();
			}

			@Override
			public boolean isDrawAllData()//是否绘制所有数据
			{
				return isNeedDrawAllData();
			}

			@Override
			public void setAdditionData(List<CandleData> pAddition)
			{
				m_AdditonData = pAddition;
			}

			@Override
			public boolean isShowShadow()
			{
				return m_bIsShowShadow;
			}


		});

		if (pNeedDraw)
		{
			if (m_callback != null)
			{
				if (m_chartData != null)
				{
					setData(m_chartData, AppDefine.UpdateMode.REFRESH);
				}
				m_callback.NeedRedraw();
			}
		}
	}

	private void checkRectF(RectF pRect)
	{
		float tLeftOffset = checkRectLimit(pRect.left);
		float tTopOffset = checkRectLimit(pRect.top);
		float tWidth = checkRectLimit(pRect.right);
		float tHeight = checkRectLimit(pRect.bottom);
		if (tLeftOffset + tWidth > 1.f)
		{
			tWidth = 1 - tLeftOffset;
		}
		if (tTopOffset + tHeight > 1.f)
		{
			tHeight = 1 - tTopOffset;
		}

		m_rect = new RectF(tLeftOffset, tTopOffset, tWidth, tHeight);
	}

	private float checkRectLimit(float pValue)
	{
		if (pValue > 1.0f)
		{
			return 1.0f;
		}
		else if (pValue < 0.f)
		{
			return 0.f;
		}
		else
		{
			return pValue;
		}
	}

	public String getID()
	{
		return m_strID;
	}

	public void setLayerRect(RectF pRect)
	{
		checkRectF(pRect);
	}

	public void isShowLayer(boolean pIsShow)
	{
		m_bIsShowLayer = pIsShow;
	}

	public boolean getShowLayer()
	{
		return m_bIsShowLayer;
	}

	public void isShowCoordinate(boolean pIsShow)
	{
		m_bIsShowCoordinate = pIsShow;
	}

	public boolean getShowCoordinate()
	{
		return m_bIsShowCoordinate;
	}


	public void needGradient(boolean gradient)
	{
		m_layerType.needGradient(gradient);
	}

	public void setCrossOutter(boolean pBool)
	{
		m_bIsCrossOutter = pBool;
	}

	public String getXText()
	{
		return m_layerType.getXText();
	}

	public String getYText()
	{
		return m_layerType.getYText();
	}

	public boolean containPoint(Point pPoint)
	{
		return m_coordinate.containPoint(pPoint);
	}

	public void setMACount(int pCount)
	{
		m_nMACount = pCount;
	}

	public void setColor(int pColor)
	{
		m_color = pColor;
	}

	public void showYesterClose(boolean pShow)
	{
		m_layerType.showYesterClose(pShow);
	}

	public void setYesterClose(float pValue)
	{
		m_layerType.setYesterClose(pValue);
	}

	public void initializeRect(RectF pRect, RectF pSpace, float textSpaceX, float textSpaceY)
	{
		if (m_bIsShowLayer)
		{
			ChartData.ChartPeroid tType = ChartData.ChartPeroid.PERFORMANCE;
			if (m_chartData != null)
			{
				tType = m_chartData.getChartPeroid();
			}
			m_coordinate.initialize(m_rect, pRect, tType, pSpace, textSpaceX, textSpaceY);
		}
	}

	public void drawLayer(Canvas pCanvas, Paint pPaint, Point pPoint)
	{
		if (m_bIsShowLayer)
		{
			if(m_bIsShowOutRect)
			{
				m_coordinate.drawOutRect(pCanvas,pPaint);
			}
			if (m_bIsShowCoordinate)
			{
				m_coordinate.drawCoordinate(pCanvas, pPaint, m_chartData);//画虚线
			}
			m_layerType.drawLayer(pCanvas, pPaint, pPoint);
			if (m_bIsShowCoordinate)
			{
				m_coordinate.drawCoordinateText(pCanvas, pPaint, m_chartData);//画坐标数字，为了使数字可以显示在图标上面，所以画后面
			}
		}
	}

	public boolean IsPointInLayer()
	{
		return m_layerType.IsPointInLayer();
	}

	public void drawCrossText(Canvas pCanvas, Paint pPaint)
	{
		m_layerType.drawCrossText(pCanvas, pPaint);
	}

	public void drawAvgPriceText(Canvas pCanvas, Paint pPaint)
	{
		m_layerType.drawAvgText(pCanvas, pPaint);
	}

	public void drawFloatPanel(Canvas pCanvas, Paint pPaint)
	{
		m_layerType.drawFloatPanel(pCanvas, pPaint);
	}

	public void drawFloatIndicatorText(boolean longtouch,Canvas pCanvas, Paint pPaint)
	{
		m_layerType.drawFloatIndicatorText(longtouch, pCanvas, pPaint);
	}


	public interface LayerCallback
	{
		void NeedRedraw();

		int getSysUpColor();

		int getSysDownColor();

		int getSysBgColor();

		int getSysEvenColor();

		ChartData.ChartPeroid getChartType();

		int getXTagCount();

		void pointFeedback(Point point, HashMap<String, String> pData);

		public void pointFeedback(HashMap<String, String> pData, Point pPoint, boolean isPointInLayer);

		Rect getPanelRect();

		boolean isSimpleMode();

		Bitmap getArrowLeft();

		Bitmap getArrowRight();

		boolean isCoordinateTextOuterY();

		void lastPoint(String pLayerID, float x, float y);

		int getDisplayCount();

		float getScaleFactor();

		boolean isInMoveMode();
	}
}
